# LeetCode 49、字母异位词分组
# 一、题目描述
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"] 输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
示例 2:
输入: strs = [""] 输出: [[""]]
示例 3:
输入: strs = ["a"] 输出: [["a"]]
提示:
1 <= strs.length <= 10^4
0 <= strs[i].length <= 100
strs[i]
仅包含小写字母
# 二、题目解析
# 三、参考代码
# 1、Java 代码
// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
// 作者:程序员吴师兄
// 微信:wzb_3377
// 代码有看不懂的地方一定要私聊咨询吴师兄呀
// 字母异位词分组(LeetCode 49):https://leetcode.cn/problems/group-anagrams/
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
// 互为字母异位词的两个字符串包含的字母相同
// 因此两个字符串中的相同字母出现的次数一定是相同的
// 可以将每个字母出现的次数使用字符串表示,作为哈希表的键
Map<String, List<String>> map = new HashMap<String, List<String>>();
for (String str : strs) {
// 由于都是小写字母,因此直接用 26 个长度的数组代替原来的 HashMap ,比直接使用 HashMap 更优秀
// counts 代表每个小写字母出现的频次
int[] counts = new int[26];
// 利用 for 循环,统计 str 当中每个字母出现的频次
for (int i = 0; i < str.length(); i++) {
// 对于数组类型,其下标为 int 类型
// 可以直接使用 char 类型变量,默认强制转换,存储的就是字母对应的 ASCII 码
// 比如 str.charAt(i) 是 b 字符,那么 b - a = 1,即 counts[1] 表示记录 b 出现的频次
counts[str.charAt(i) - 'a']++;
}
// String 类是不可变类,即一旦一个 String 对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。
// Java 提供了两个可变字符串类 StringBuffer 和 StringBuilder,中文翻译为“字符串缓冲区”
// StringBuffer:线程安全
// StringBuilder:线程不安全
StringBuffer sb = new StringBuffer();
// 将每个出现次数大于 0 的字母和出现次数按顺序拼接成字符串,作为哈希表的键
for (int i = 0; i < 26; i++) {
if (counts[i] != 0) {
// 先记录字母,比如记录了字母 k
sb.append((char) ('a' + i));
// 再记录次数,比如记录了次数 9
sb.append(counts[i]);
}
}
// 转换为字符串的形式,比如为 a1k9x7
String key = sb.toString();
// 在哈希表 map 当中找出这个 key 对应的字符串 str 来
// 1、如果有这个 key,那么这个 key 对应的 数组 会新增一个 str 进去
// 2、如果没有这个 key,那么会初始化一个数组,用来新增这个 str
List<String> list = map.getOrDefault(key, new ArrayList<String>());
// str 加入到 list 当中
list.add(str);
// map 进行更新
map.put(key, list);
}
// 返回结果
return new ArrayList<List<String>>(map.values());
}
}
# **2、**C++ 代码
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
// 互为字母异位词的两个字符串包含的字母相同
// 因此两个字符串中的相同字母出现的次数一定是相同的
// 可以将每个字母出现的次数使用字符串表示,作为哈希表的键
unordered_map<string, vector<string>> mp;
for (string& str : strs) {
// counts 代表每个小写字母出现的频次
vector<int> counts(26);
// 利用 for 循环,统计 str 当中每个字母出现的频次
for (char c : str) {
counts[c - 'a']++;
}
// 将每个出现次数大于 0 的字母和出现次数按顺序拼接成字符串,作为哈希表的键
string key;
for (int count : counts) {
key += '#';
key += to_string(count);
}
// 在哈希表 mp 当中找出这个 key 对应的字符串 str 来
// 1、如果有这个 key,那么这个 key 对应的 数组 会新增一个 str 进去
// 2、如果没有这个 key,那么会初始化一个数组,用来新增这个 str
mp[key].emplace_back(str);
}
// 返回结果
vector<vector<string>> res;
for (auto& p : mp) {
res.emplace_back(p.second);
}
return res;
}
};
# 3、Python 代码
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
# 互为字母异位词的两个字符串包含的字母相同
# 因此两个字符串中的相同字母出现的次数一定是相同的
# 可以将每个字母出现的次数使用字符串表示,作为哈希表的键
mp = collections.defaultdict(list)
for s in strs:
# counts 代表每个小写字母出现的频次
counts = [0] * 26
# 利用 for 循环,统计 str 当中每个字母出现的频次
for c in s:
counts[ord(c) - ord('a')] += 1
# 将每个出现次数大于 0 的字母和出现次数按顺序拼接成字符串,作为哈希表的键
key = ''.join(['#'+str(count) for count in counts])
# 在哈希表 mp 当中找出这个 key 对应的字符串 str 来
# 1、如果有这个 key,那么这个 key 对应的 数组 会新增一个 str 进去
# 2、如果没有这个 key,那么会初始化一个数组,用来新增这个 str
mp[key].append(s)
# 返回结果
return list(mp.values())
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
# 互为字母异位词的两个字符串包含的字母相同
# 因此两个字符串中的相同字母出现的次数一定是相同的
# 可以将每个字母出现的次数使用字符串表示,作为哈希表的键
mp = collections.defaultdict(list)
for s in strs:
# counts 代表每个小写字母出现的频次
counts = [0] * 26
# 利用 for 循环,统计 str 当中每个字母出现的频次
for c in s:
counts[ord(c) - ord('a')] += 1
# 将每个出现次数大于 0 的字母和出现次数按顺序拼接成字符串,作为哈希表的键
key = ''.join(['#'+str(count) for count in counts])
# 在哈希表 mp 当中找出这个 key 对应的字符串 str 来
# 1、如果有这个 key,那么这个 key 对应的 数组 会新增一个 str 进去
# 2、如果没有这个 key,那么会初始化一个数组,用来新增这个 str
mp[key].append(s)
# 返回结果
return list(mp.values())